// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBManager/Repository/HDF5/Input/Design/TOPVARRepository.h"

#include "DBManager/Repository/HDF5/Base/HDF5RepositoryMacro.h"

HDF5_REG_REPOSITORY (TOPVARRepository)

using namespace SG::DBManager::HDF5;
using namespace SG::DataStructure;
using namespace SG::DataStructure::FEM;
using namespace SG::DataStructure::Common;

// 构造函数实现
TOPVARRepository::TOPVARRepository (HDF5Database& database) : SG::DBManager::HDF5::MainlyRepositoryBase<MainStruct> (database)
{}

void TOPVARRepository::InitialDatasetInfo ()
{
    RegisterTableInfo<SG::DataStructure::Common::Id> ("/OWN/INDEX/INPUT/DESIGN/TOPVAR", IndexDataset);
    RegisterTableInfo<NasMainStruct> ("/SG/INPUT/DESIGN/TOPVAR/IDENTITY", MainDataset);
    RegisterTableInfo<SubStructCAST> ("/SG/INPUT/DESIGN/TOPVAR/CAST", SubDataset_CAST);
    RegisterTableInfo<SubStructEXT> ("/SG/INPUT/DESIGN/TOPVAR/EXTRUSION", SubDataset_EXT);
    RegisterTableInfo<SubStructMIN> ("/SG/INPUT/DESIGN/TOPVAR/MIN", SubDataset_MIN);
    RegisterTableInfo<SubStructPRINT> ("/SG/INPUT/DESIGN/TOPVAR/PRINT", SubDataset_PRINT);
    RegisterTableInfo<SubStructSTRESS> ("/SG/INPUT/DESIGN/TOPVAR/STRESS", SubDataset_STRESS);
    RegisterTableInfo<SubStructSYM> ("/SG/INPUT/DESIGN/TOPVAR/SYMPLANE", SubDataset_SYM);
}

void TOPVARRepository::DumpWriteCahce ()
{
    auto& writeStorage = this->GetMainCache ().m_writeStorage;

    // 1. flag设置为无顺序
    GetMainDatasetInfo ().SetIsSequential (false);

    // 主表数据
    std::vector<NasMainStruct> IDENTITYData{};
    // 附表数据
    std::vector<SubStructCAST>   subDataCAST;
    std::vector<SubStructEXT>    subDataEXT;
    std::vector<SubStructMIN>    subDataMIN;
    std::vector<SubStructPRINT>  subDataPRINT;
    std::vector<SubStructSTRESS> subDataSTRESS;
    std::vector<SubStructSYM>    subDataSYM;

    // 2. 转换为nastran格式数据
    OwnToNastran (writeStorage, IDENTITYData, subDataCAST, subDataEXT, subDataMIN, subDataPRINT, subDataSTRESS, subDataSYM);

    // 3. 写出数据至文件
    WriteData (MainDataset, IDENTITYData);
    WriteData (SubDataset_CAST, subDataCAST);
    WriteData (SubDataset_EXT, subDataEXT);
    WriteData (SubDataset_MIN, subDataMIN);
    WriteData (SubDataset_PRINT, subDataPRINT);
    WriteData (SubDataset_STRESS, subDataSTRESS);
    WriteData (SubDataset_SYM, subDataSYM);

    // 4. 更新Index表
    this->WriteIndexData (this->GetIndexDatasetInfo (), writeStorage);

    // 5. 清空缓存
    writeStorage.clear ();
}

std::vector<TOPVARRepository::DataType>* TOPVARRepository::LoadReadCache (std::size_t loadIndex)
{
    // 1. 读取范围内主表数据
    std::vector<NasMainStruct> IDENTITYData;
    LoadMainMetadata (loadIndex, IDENTITYData);

    if (IDENTITYData.empty ())
    {
        return nullptr;
    }

    // 2. 读取范围内附表数据
    std::vector<SubStructCAST>   subDataCAST;
    std::vector<SubStructEXT>    subDataEXT;
    std::vector<SubStructMIN>    subDataMIN;
    std::vector<SubStructPRINT>  subDataPRINT;
    std::vector<SubStructSTRESS> subDataSTRESS;
    std::vector<SubStructSYM>    subDataSYM;

    LoadSecondaryMetadata (IDENTITYData, CAST_POS, CAST_LEN, SubDataset_CAST, subDataCAST);
    LoadSecondaryMetadata (IDENTITYData, EXT_POS, EXT_LEN, SubDataset_EXT, subDataEXT);
    LoadSecondaryMetadata (IDENTITYData, MIN_POS, MIN_LEN, SubDataset_MIN, subDataMIN);
    LoadSecondaryMetadata (IDENTITYData, PRINT_POS, PRINT_LEN, SubDataset_PRINT, subDataPRINT);
    LoadSecondaryMetadata (IDENTITYData, STRESS_POS, STRESS_LEN, SubDataset_STRESS, subDataSTRESS);
    LoadSecondaryMetadata (IDENTITYData, SYM_POS, SYM_LEN, SubDataset_SYM, subDataSYM);

    // 3. 将数据转换为自己的格式放入缓存
    auto* cacheVector = m_cacheHelper.LookupOrCreateVector<DataType> (GetMainCache ().m_readCacheKey, IDENTITYData.size ());
    NastranToOwn (IDENTITYData, subDataCAST, subDataEXT, subDataMIN, subDataPRINT, subDataSTRESS, subDataSYM, *cacheVector);
    return cacheVector;
}

void TOPVARRepository::SortData ()
{
    // 1. 读取主表数据
    std::vector<NasMainStruct> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        GetMainDatasetInfo ().SetIsSequential (true);
        return;
    }

    // 2. 读取附表数据
    std::vector<SubStructCAST>   subDataCAST;
    std::vector<SubStructEXT>    subDataEXT;
    std::vector<SubStructMIN>    subDataMIN;
    std::vector<SubStructPRINT>  subDataPRINT;
    std::vector<SubStructSTRESS> subDataSTRESS;
    std::vector<SubStructSYM>    subDataSYM;

    GetDataset (SubDataset_CAST).read (subDataCAST);
    GetDataset (SubDataset_EXT).read (subDataEXT);
    GetDataset (SubDataset_MIN).read (subDataMIN);
    GetDataset (SubDataset_PRINT).read (subDataPRINT);
    GetDataset (SubDataset_STRESS).read (subDataSTRESS);
    GetDataset (SubDataset_SYM).read (subDataSYM);

    // 3. 将所有数据转换
    std::vector<MainStruct> AllData{};
    NastranToOwn (IDENTITYData, subDataCAST, subDataEXT, subDataMIN, subDataPRINT, subDataSTRESS, subDataSYM, AllData);

    // 4. 排序
    std::sort (AllData.begin (), AllData.end ());

    // 5. 转换回nastran格式
    OwnToNastran (AllData, IDENTITYData, subDataCAST, subDataEXT, subDataMIN, subDataPRINT, subDataSTRESS, subDataSYM, true);

    // 6. 写出主表数据至文件
    GetDataset (MainDataset).write (IDENTITYData);
    // 7. 写出附表数据至文件
    GetDataset (SubDataset_CAST).write (subDataCAST);
    GetDataset (SubDataset_EXT).write (subDataEXT);
    GetDataset (SubDataset_MIN).write (subDataMIN);
    GetDataset (SubDataset_PRINT).write (subDataPRINT);
    GetDataset (SubDataset_STRESS).write (subDataSTRESS);
    GetDataset (SubDataset_SYM).write (subDataSYM);

    // 8. 重写索引
    RewriteIndexData (AllData);

    // 9. 设置为已顺序
    GetMainDatasetInfo ().SetIsSequential (true);
}

std::vector<TOPVARRepository::MainStruct> TOPVARRepository::GetAllData ()
{
    Sort ();

    std::vector<MainStruct> result;

    std::vector<NasMainStruct> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        return result;
    }

    std::vector<SubStructCAST>   subDataCAST;
    std::vector<SubStructEXT>    subDataEXT;
    std::vector<SubStructMIN>    subDataMIN;
    std::vector<SubStructPRINT>  subDataPRINT;
    std::vector<SubStructSTRESS> subDataSTRESS;
    std::vector<SubStructSYM>    subDataSYM;

    GetDataset (SubDataset_CAST).read (subDataCAST);
    GetDataset (SubDataset_EXT).read (subDataEXT);
    GetDataset (SubDataset_MIN).read (subDataMIN);
    GetDataset (SubDataset_PRINT).read (subDataPRINT);
    GetDataset (SubDataset_STRESS).read (subDataSTRESS);
    GetDataset (SubDataset_SYM).read (subDataSYM);

    // 将所有数据转换
    NastranToOwn (IDENTITYData, subDataCAST, subDataEXT, subDataMIN, subDataPRINT, subDataSTRESS, subDataSYM, result);

    return result;
}

void TOPVARRepository::OwnToNastran (std::vector<MainStruct>&           own,
                                     std::vector<NasMainStruct>& _OUT   IDENTITYData,
                                     std::vector<SubStructCAST>& _OUT   subDataCAST,
                                     std::vector<SubStructEXT>& _OUT    subDataEXT,
                                     std::vector<SubStructMIN>& _OUT    subDataMIN,
                                     std::vector<SubStructPRINT>& _OUT  subDataPRINT,
                                     std::vector<SubStructSTRESS>& _OUT subDataSTRESS,
                                     std::vector<SubStructSYM>& _OUT    subDataSYM,

                                     bool isSort)
{
    subDataCAST.clear ();
    subDataEXT.clear ();
    subDataMIN.clear ();
    subDataPRINT.clear ();
    subDataSTRESS.clear ();
    subDataSYM.clear ();

    IDENTITYData.clear ();
    IDENTITYData.reserve (own.size ());

    // 获取已有数据条数，主要是放在主表的POS字段
    // 如果是重新排序的时候，Pos都是从0 开始的
    size_t countCAST   = isSort ? 0 : this->GetDatasetInfo (SubDataset_CAST).GetRowCount ();
    size_t countEXT    = isSort ? 0 : this->GetDatasetInfo (SubDataset_EXT).GetRowCount ();
    size_t countMIN    = isSort ? 0 : this->GetDatasetInfo (SubDataset_MIN).GetRowCount ();
    size_t countPRINT  = isSort ? 0 : this->GetDatasetInfo (SubDataset_PRINT).GetRowCount ();
    size_t countSTRESS = isSort ? 0 : this->GetDatasetInfo (SubDataset_STRESS).GetRowCount ();
    size_t countSYM    = isSort ? 0 : this->GetDatasetInfo (SubDataset_SYM).GetRowCount ();

    // OwnIdent 代表咱们自己的数据结构
    // NasIdent 代表nastran的数据结构
    for (auto& OwnIdent : own)
    {
        // 写入附表
        subDataCAST.insert (subDataCAST.end (), OwnIdent.m_CASTList.begin (), OwnIdent.m_CASTList.end ());
        subDataEXT.insert (subDataEXT.end (), OwnIdent.m_EXTRUSIONList.begin (), OwnIdent.m_EXTRUSIONList.end ());
        subDataMIN.insert (subDataMIN.end (), OwnIdent.m_MINList.begin (), OwnIdent.m_MINList.end ());
        subDataPRINT.insert (subDataPRINT.end (), OwnIdent.m_PRINTList.begin (), OwnIdent.m_PRINTList.end ());
        subDataSTRESS.insert (subDataSTRESS.end (), OwnIdent.m_STRESSList.begin (), OwnIdent.m_STRESSList.end ());
        subDataSYM.insert (subDataSYM.end (), OwnIdent.m_SYMPLANEList.begin (), OwnIdent.m_SYMPLANEList.end ());

        const size_t lenCAST   = OwnIdent.m_CASTList.size ();
        const size_t lenEXT    = OwnIdent.m_EXTRUSIONList.size ();
        const size_t lenMIN    = OwnIdent.m_MINList.size ();
        const size_t lenPRINT  = OwnIdent.m_PRINTList.size ();
        const size_t lenSTRESS = OwnIdent.m_STRESSList.size ();
        const size_t lenSYM    = OwnIdent.m_SYMPLANEList.size ();

        // 写入IDENTITY
        NasMainStruct NasIdent{};

        NasIdent.TOPID = OwnIdent.m_id;
        memcpy (NasIdent.LABEL, OwnIdent.m_LABEL, 8);
        memcpy (NasIdent.PTYPE, OwnIdent.m_PTYPE, 8);
        NasIdent.XINIT     = OwnIdent.m_XINIT;
        NasIdent.XLB       = OwnIdent.m_XLB;
        NasIdent.DELXV     = OwnIdent.m_DELXV;
        NasIdent.POWER     = OwnIdent.m_POWER;
        NasIdent.PID       = OwnIdent.m_pId;
        NasIdent.DOMAIN_ID = OwnIdent.m_domainId;

        NasIdent.CAST_POS   = static_cast<I64> (countCAST);
        NasIdent.EXT_POS    = static_cast<I64> (countEXT);
        NasIdent.MIN_POS    = static_cast<I64> (countMIN);
        NasIdent.PRINT_POS  = static_cast<I64> (countPRINT);
        NasIdent.STRESS_POS = static_cast<I64> (countSTRESS);
        NasIdent.SYM_POS    = static_cast<I64> (countSYM);

        NasIdent.CAST_LEN   = static_cast<I64> (lenCAST);
        NasIdent.EXT_LEN    = static_cast<I64> (lenEXT);
        NasIdent.MIN_LEN    = static_cast<I64> (lenMIN);
        NasIdent.PRINT_LEN  = static_cast<I64> (lenPRINT);
        NasIdent.STRESS_LEN = static_cast<I64> (lenSTRESS);
        NasIdent.SYM_LEN    = static_cast<I64> (lenSYM);

        IDENTITYData.emplace_back (NasIdent);

        countCAST += lenCAST;
        countEXT += lenEXT;
        countMIN += lenMIN;
        countPRINT += lenPRINT;
        countSTRESS += lenSTRESS;
        countSYM += lenSYM;
    }
}

void TOPVARRepository::NastranToOwn (std::vector<NasMainStruct>&   IDENTITYData,
                                     std::vector<SubStructCAST>&   subDataCAST,
                                     std::vector<SubStructEXT>&    subDataEXT,
                                     std::vector<SubStructMIN>&    subDataMIN,
                                     std::vector<SubStructPRINT>&  subDataPRINT,
                                     std::vector<SubStructSTRESS>& subDataSTRESS,
                                     std::vector<SubStructSYM>&    subDataSYM,

                                     std::vector<MainStruct>& _OUT own)
{
    own.clear ();
    own.reserve (IDENTITYData.size ());

    // 代表初始的Index 位置,
    // 因为数据有可能是截取了附表的一部分，所有主表中根据POS找的时候需要对应一下，
    // 比如第一个主表数据中POS字段为10000， 附表的vector的数据
    // 就是从附表中的第10000个开始对应的 也就是Index==0的
    // const I64 index = IDENTITYData[0].POS;

    MainStruct const tempown;
    own.resize (IDENTITYData.size (), tempown);

    for (size_t i = 0; i < IDENTITYData.size (); i++)
    {
        auto& OwnIdent = own[i];
        auto& NasIdent = IDENTITYData[i];

        OwnIdent.m_id = NasIdent.TOPID;
        memcpy (OwnIdent.m_LABEL, NasIdent.LABEL, 8);
        memcpy (OwnIdent.m_PTYPE, NasIdent.PTYPE, 8);
        OwnIdent.m_XINIT    = NasIdent.XINIT;
        OwnIdent.m_XLB      = NasIdent.XLB;
        OwnIdent.m_DELXV    = NasIdent.DELXV;
        OwnIdent.m_POWER    = NasIdent.POWER;
        OwnIdent.m_pId      = NasIdent.PID;
        OwnIdent.m_domainId = NasIdent.DOMAIN_ID;

        if (NasIdent.CAST_LEN != 0)
        {
            OwnIdent.m_CASTList.assign (subDataCAST.begin () + NasIdent.CAST_POS - IDENTITYData[0].CAST_POS,
                                        subDataCAST.begin () + NasIdent.CAST_POS + NasIdent.CAST_LEN - IDENTITYData[0].CAST_POS);
        }
        if (NasIdent.EXT_LEN != 0)
        {
            OwnIdent.m_EXTRUSIONList.assign (subDataEXT.begin () + NasIdent.EXT_POS - IDENTITYData[0].EXT_POS,
                                             subDataEXT.begin () + NasIdent.EXT_POS + NasIdent.EXT_LEN - IDENTITYData[0].EXT_POS);
        }
        if (NasIdent.MIN_LEN != 0)
        {
            OwnIdent.m_MINList.assign (subDataMIN.begin () + NasIdent.MIN_POS - IDENTITYData[0].MIN_POS,
                                       subDataMIN.begin () + NasIdent.MIN_POS + NasIdent.MIN_LEN - IDENTITYData[0].MIN_POS);
        }
        if (NasIdent.PRINT_LEN != 0)
        {
            OwnIdent.m_PRINTList.assign (subDataPRINT.begin () + NasIdent.PRINT_POS - IDENTITYData[0].PRINT_POS,
                                         subDataPRINT.begin () + NasIdent.PRINT_POS + NasIdent.PRINT_LEN - IDENTITYData[0].PRINT_POS);
        }
        if (NasIdent.STRESS_LEN != 0)
        {
            OwnIdent.m_STRESSList.assign (subDataSTRESS.begin () + NasIdent.STRESS_POS - IDENTITYData[0].STRESS_POS,
                                          subDataSTRESS.begin () + NasIdent.STRESS_POS + NasIdent.STRESS_LEN - IDENTITYData[0].STRESS_POS);
        }
        if (NasIdent.SYM_LEN != 0)
        {
            OwnIdent.m_SYMPLANEList.assign (subDataSYM.begin () + NasIdent.SYM_POS - IDENTITYData[0].SYM_POS,
                                            subDataSYM.begin () + NasIdent.SYM_POS + NasIdent.SYM_LEN - IDENTITYData[0].SYM_POS);
        }
    }
}
